﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Xml.Linq;
using System.Globalization;

namespace DbSharp.Framework.ReleaseManage
{
    /// <summary>
    /// one service can retrieve the current datetime
    /// </summary>
    public interface IDateTimeService
    {
        /// <summary>
        /// to get current datetime
        /// </summary>
        /// <returns></returns>
        DateTime GetCurrentTime();
    }

     
    /// <summary>
    /// one Web Service, that can retrieve the current datetime
    /// </summary>
    class EarthtoolsDateWebService : IDateTimeService
    {
        private long m_LastRequestTimeTicks;
        private long m_OneDayTicks;
        private DateTime m_ActualTodayTime;
        private IDateWebServiceCache m_localCache;

        private long GetOneDayTicks()
        {
            DateTime today = DateTime.Today;
            return today.AddDays(1).Ticks - today.Ticks;
        }

        private DateTime GetWebTime()
        {
            DateTime result = m_ActualTodayTime;
            try
            {
                using (WebClient wc = new WebClient())
                {
                    //request NewYork time
                    var webResponse = wc.DownloadString(@"http://www.earthtools.org/timezone/40.71417/-74.00639");
                    var xdoc = XDocument.Parse(webResponse);

                    //please refer the file WebServiceResponse.xml
                    string dateString = xdoc.Descendants("utctime").First().Value;
                    //format is "2008-12-01 04:28:29";
                    string dateFmt = "yyyy-MM-dd hh:mm:ss";
                    var styles = DateTimeStyles.AllowWhiteSpaces;

                    DateTime webTodayTime;
                    if (DateTime.TryParseExact(dateString, dateFmt, null, styles, out webTodayTime) == false)
                    {
                        return result;
                    }
                    else
                    {
                        //the result will be the later one date of webDate and localDate
                        if (result.CompareTo(webTodayTime) < 0)
                            result = webTodayTime;
                        return result;
                    }
                }
            }
            catch { }
            return result;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <exception cref="">
        /// if app config is bad, an exception will be thrown. 
        /// </exception>
        /// <param name="localCache"></param>
        public EarthtoolsDateWebService(IDateWebServiceCache localCache)
        {
            m_OneDayTicks = GetOneDayTicks();
            m_localCache = localCache;
            //The following code may be throw exception because of the bad config file
            m_LastRequestTimeTicks = m_localCache.GetLastRequestTimeTicks();
            try
            {
                m_ActualTodayTime = new DateTime(m_LastRequestTimeTicks);
            }
            catch
            {
                m_ActualTodayTime = DateTime.Now;
            }

            if (m_ActualTodayTime.CompareTo(DateTime.Now) < 0)
                m_ActualTodayTime = DateTime.Now;
        }


        

       

        #region IDateTimeService Members


        /// <summary>
        /// the result will be the later one date of webDate and localDate
        /// </summary>
        /// <returns></returns>
        public DateTime GetCurrentTime()
        {
            DateTime result = m_ActualTodayTime;

            //You must not make more than one request per second to these webservices.
            if (m_ActualTodayTime.Ticks - m_LastRequestTimeTicks >= m_OneDayTicks)
            {
                result = GetWebTime();
            }

            try
            {
                m_localCache.CacheRequestTimeTicks(result.Ticks);
            }
            catch { }

            return result;
        }

        #endregion
    }



    /// <summary>
    /// one service to return current Operating System datetime
    /// </summary>
    class LocalMachineDateService : IDateTimeService
    {
        #region IDateTimeService Members

        public DateTime GetCurrentTime()
        {
            return DateTime.Now;
        }

        #endregion
    }
}
